
//  FileTransfer.m
//  HiQ
//
//  Created by scarlettsun on 12-8-16.
//  Copyright (c) 2012年 tencent. All rights reserved.
//

#import "FileTransfer.h"
#import "FileWindowController.h"
#import "MainWindowController.h"
#import "MacrosDefine.h"


@implementation FileTransfer
@synthesize transferEntity;

- (void) initWithSock:(FileSocket *)sock
{
    fileSock = sock ;
    sock.delegate = self;
    receiveCounter = 0;
    sendCounter = 0;
}

//终止发送
- (void) terminateTransfer
{
    [fileSock.fileAsynSocket disconnect];
}

- (FileTransfer *)initWithEntity:(FileEntity *)entity
{
    /*创建FileSocket to send file*/
    self.transferEntity = entity;
    entity.delegate = self;
    return self;
}

#pragma mark fileEntityDelegate

//响应用户接收文件事件
- (void)doAcceptFile
{
    NSString * msg = @"accept";
    NSUInteger dataLength = msg.length+16;
    NSUInteger fun = CMD_FUN_FILE;
    NSUInteger subfun = CMD_FUN_FILE_ACCEPT;
    NSMutableData *data = [NSMutableData dataWithBytes:&(dataLength) length:sizeof(NSUInteger)];
    [data appendBytes:&(fun) length:sizeof(NSUInteger)];
    [data appendBytes:&(subfun) length:sizeof(NSUInteger)];
    [data appendBytes:[[msg dataUsingEncoding: NSUTF8StringEncoding] bytes] length:msg.length];
    [fileSock.fileAsynSocket writeData: data withTimeout: -1 tag: 0];
}

//响应用户拒绝接收文件或取消发送文件事件
- (void)doRejectFile
{
    NSString * msg = @"reject";
    NSUInteger fun = CMD_FUN_FILE;
    NSUInteger subfun = CMD_FUN_FILE_REJECT;
    transferEntity.fileState = EntityReject;
    if(transferEntity.receiverId != ((MainWindowController*)[MainWindowController sharedMainWindowController]).myselfInfo.buddyQQ)
    {
        subfun = CMD_FUN_FILE_CANCEL ;
        transferEntity.fileState = EntityCancel;
        msg = @"cancel is sent ";
    }
    NSUInteger dataLength = msg.length+16;
    NSMutableData *data = [NSMutableData dataWithBytes:&(dataLength) length:sizeof(NSUInteger)];
    [data appendBytes:&(fun) length:sizeof(NSUInteger)];
    [data appendBytes:&(subfun) length:sizeof(NSUInteger)];
    [data appendBytes:[[msg dataUsingEncoding: NSUTF8StringEncoding] bytes] length:msg.length];
    [fileSock.fileAsynSocket writeData: data withTimeout: -1 tag: 0];
    [self showFilePanel];
}

//响应用户终止文件传送事件
- (void)doTerminateFile
{
    [fileSock.fileAsynSocket disconnect];  
}

- (void) showFilePanel //更新文件面板
{
    dispatch_async(dispatch_get_main_queue(), ^{
        
        switch ([FileWindowController FileIfShow]) 
        {
            case Open:  //打开状态
                [[FileWindowController fileWindowController] updateFileProgress]; 
                break;
            case UnOpen: //已初始化，未打开
                [[FileWindowController fileWindowController] showWindow: nil];
                break;
            case Close:  //主动关闭状态
                break;
            default:
                break;
        }
    });
}


#pragma mark filetransfer delegate
- (void)sendFileInfo:(Buddy*)peerBuddy
{
    FileSocket *sock = [[FileSocket alloc] init]; 
    GCDAsyncSocket *sendSocket  = [[GCDAsyncSocket alloc] initWithDelegate:sock delegateQueue:dispatch_queue_create("filesockqueue", 0)];
    NSError *error;
    BOOL connectOK = [sendSocket connectToHost:peerBuddy.ip onPort: peerBuddy.listenPort error: &error];        
    if (!connectOK)
    {         
        NSString * errMsg = [[error localizedDescription] stringByAppendingFormat:NSLocalizedString(@"\r\n ip: %@, port:%lu", nil),peerBuddy.ip,peerBuddy.listenPort]; 
        [self showError:errMsg];
        return;
    }
    if (transferEntity != nil)
    {
        [[FileWindowController fileWindowController].fileListArray addObject:transferEntity]; 
        sock = [sock initWithSock:sendSocket]; 
        sock.delegate = self;
        fileSock = sock;
        [[FileListenSocket fileSocketsQueue] addObject:sock]; 
        
        /*发送文件信息*/
        NSUInteger fileSize = transferEntity.fileSize; 
        NSUInteger senderId = transferEntity.senderId; 
        NSData *fileName = [[transferEntity.fileUrl lastPathComponent] dataUsingEncoding:NSUTF8StringEncoding];
        NSUInteger dataLength = fileName.length+32;
        NSUInteger fun = CMD_FUN_FILE;
        NSUInteger subfun = CMD_FUN_FILE_REQUEST;
        NSMutableData *data = [NSMutableData dataWithBytes:&(dataLength) length:sizeof(NSUInteger)];
        [data appendBytes:&(fun) length:sizeof(NSUInteger)];
        [data appendBytes:&(subfun) length:sizeof(NSUInteger)];
        [data appendBytes:&(fileSize) length:sizeof(NSUInteger)];
        [data appendBytes:&(senderId) length:sizeof(NSUInteger)];
        [data appendBytes:[fileName bytes] length:fileName.length];
        [transferEntity.fileHandler seekToFileOffset:transferEntity.fileSentSize];
        [sock.fileAsynSocket writeData: data withTimeout: -1 tag: 0];
        if (sock != nil) 
        {
            [self showFilePanel];
        }
    }
}
- (void)sendFIleContent
{
    if (transferEntity == nil) {
        NSLog(@"there is no file to be sent in this sock :ip is %@, port is %u", fileSock.fileAsynSocket.localHost,fileSock.fileAsynSocket.localPort);
        [fileSock.fileAsynSocket disconnect];
        return;
    }
    if (transferEntity.fileState != EntityReceive) {
         NSLog(@"file hasnt been accept");
        return;
    }
    /*继续发送文件*/
    if (transferEntity !=nil && transferEntity.fileState == EntityReceive ) 
    {
        if (transferEntity.fileSentSize < transferEntity.fileSize)
        {
            NSUInteger readLen = (transferEntity.fileSize-transferEntity.fileSentSize) > BUFFERSIZE_FILE? BUFFERSIZE_FILE :(transferEntity.fileSize-transferEntity.fileSentSize);
            NSUInteger fun = CMD_FUN_FILE;
            NSUInteger subfun = CMD_FUN_FILE_CONTENT;
            NSUInteger dataLen = readLen + 16;
            NSMutableData * data = [[NSMutableData alloc] initWithBytes:&(dataLen) length:sizeof(NSUInteger)];
            [data appendBytes:&(fun) length:sizeof(NSUInteger)];
            [data appendBytes:&(subfun) length:sizeof(NSUInteger)];
            [data appendData:[transferEntity.fileHandler readDataOfLength:readLen]];
            transferEntity.fileSentSize += readLen;
            transferEntity.fileState = EntityReceive;
            [transferEntity.fileHandler seekToFileOffset:transferEntity.fileSentSize];
            [fileSock.fileAsynSocket writeData: data withTimeout: -1 tag: 0];
            if (sendCounter < REFRESHTIME) 
                sendCounter ++;
            else 
            {
                [self showFilePanel];
                sendCounter = 0;
            }
        }
        else
        {
            transferEntity.fileState = EntityFinish;
            [self showFilePanel];
        }
    }
    else 
    {
        [fileSock.fileAsynSocket disconnect];
    }
}
- (Boolean)receiveFileInfo:(NSData *)data
{
    UTF8Char * bytes = (UTF8Char*)[data bytes];
    NSUInteger datalen = [data length];
    NSUInteger fileSize = *((NSUInteger *)([data bytes]+16)); 
    NSUInteger senderId = *((NSUInteger *)([data bytes]+24)); 
    NSString * filePath = [NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES) objectAtIndex:0];;
    NSString *fileName = [[NSString alloc]initWithBytes:(bytes+32)length:(datalen-32) encoding:NSUTF8StringEncoding];
    filePath = [filePath stringByAppendingFormat:@"/%@",fileName];
    FileEntity * entity = [[FileEntity alloc] initWithFilePath:[NSURL fileURLWithPath:filePath] senderId:senderId receiver:((MainWindowController*)[MainWindowController sharedMainWindowController]).myselfInfo fileSize:fileSize];
    transferEntity = entity;
    entity.delegate = self;
    [[FileWindowController fileWindowController].fileListArray addObject:entity];  //添加到文件接收队列
    [self showFilePanel];
    return TRUE;
}
- (Boolean)receiveFileContent:(NSData *)data
{
    NSUInteger datalen = [data length];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:[transferEntity.fileUrl path]])  //不存在创建，存在覆盖
    {
        if (![fileManager createFileAtPath:[transferEntity.fileUrl path] contents:nil attributes:nil]) 
        {
            [self showError:[NSString stringWithFormat:NSLocalizedString(@"文件%@创建失败",nil),[transferEntity.fileUrl path]]];
            return FALSE;
        }
    }
    transferEntity.fileState = EntityReceive ;//开始接收文件
    NSData * fileData = [NSData dataWithBytes:([data bytes]+16) length:datalen-16];
    if (transferEntity != nil) 
    {
        transferEntity.fileHandler = [NSFileHandle fileHandleForUpdatingAtPath:[transferEntity.fileUrl path]];
        [transferEntity.fileHandler seekToFileOffset:transferEntity.fileReceiveSize];
        [transferEntity.fileHandler writeData: fileData];
        transferEntity.fileReceiveSize += (datalen-16);
        
        if (transferEntity.fileReceiveSize < transferEntity.fileSize )
        {
            if (receiveCounter < REFRESHTIME) 
                receiveCounter ++;
            else 
            {
                [self showFilePanel];
                receiveCounter = 0;
            }
        }
        else 
        {
            transferEntity.fileState = EntityFinish;
            [self showFilePanel];
            
        }
    }  
    return TRUE;
}

- (void)fileAccept
{
    transferEntity.fileState = EntityReceive;
    [self sendFIleContent];
}
- (void)fileReject
{
    transferEntity.fileState = EntityReject;
    [self showFilePanel];
    [self terminateTransfer];    
}

-(void) fileCancel
{
    transferEntity.fileState = EntityCancel;
    [self showFilePanel];
    [self terminateTransfer];
}

- (void)fileSocketDisConnect
{
    if (transferEntity != nil) 
    {
        switch (transferEntity.fileState)
        {
            case EntityFinish:
            case EntityReject: 
            case EntityCancel:
            case EntityStop:
                break;
            case EntityReceive:
            {
                transferEntity.fileState = EntityStop;
                break;
            }
            case EntityWaiting:
            {
                transferEntity.fileState = EntityStop;
                break;
            }
            default:
                break;
        }
    }
    [self showFilePanel];
}

#pragma mark show alertview

-(void)showError:(NSString *)infoText
{
  dispatch_async(dispatch_get_main_queue(), ^{
    NSAlert *alert = [[NSAlert alloc] init];
    [alert addButtonWithTitle:NSLocalizedString(@"确定", nil)];
    [alert setMessageText:NSLocalizedString(@"连接失败",nil)];
    [alert setInformativeText:NSLocalizedString(infoText, nil)];
    [alert setAlertStyle:NSWarningAlertStyle];
    [alert beginSheetModalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(sheetClosed:returnCode:contextInfo:) contextInfo:nil];
  });
}

-(void)sheetClosed:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
    if (returnCode == NSAlertDefaultReturn) {
        [(__bridge_transfer NSWindow *)contextInfo close];
    }
}

@end
